/*
    Contact info:
    bhepple@freeshell.org
    http://bhepple.freeshell.org/scrmgr

    Copyright (C) 1991-2008 Bob Hepple

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; see the file COPYING.  If not, write to
    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
    Boston, MA 02111-1307, USA.

*/
#include <getopt.h>
#include <setjmp.h>

#include "smlib.h"

CHAR *sm2c_rcsid(void) {
    return("$Id: sm2c.c,v 1.7 2008/02/19 13:15:50 bhepple Exp $");
}

extern int	errno;

static CHAR	rev_string[] = "$Revision: 1.7 $";
jmp_buf		NoMoreHeap;

static CHAR *usage_msg[] = {
"Reads SCRMGR files and outputs boiler plate statements for \'c\'.",
"Scrmgr-files usally have a '.dat' name extension. Files *.def and *.opn are",
"created for defining scrmgr objects (*.def) and opening them ready",
"for use (*.opn). These files can then be included in an",
"application.",
NULL
};

void usage()
{
    CHAR **c;
    
    fprintf(stderr, "Revision %s of %s.\n", rev_string, sm_program_name);
    fprintf(stderr, "Usage: %s scrmgr-file\n", sm_program_name);
    
    c = usage_msg;
    while (*c) {
        fputs(*c, stderr);
        fputc('\n', stderr);
        c++;
    }
    exit(2);
}

/* stub */
void sm_error_exit ARG1(CHAR *, msg)
{
}

/* Stubs to be overidden if needed (at the moment, only if your application
   uses field triggers) */

f_ptr sm_get_field_trigger ARG1(SM_FIELD, field)
{
    return(NULL);
}

int compare_skey ARG2(const void *, a1, const void *, a2)
{
    return(strcmp((*(SM_KEYWORD *)a1)->string, (*(SM_KEYWORD *)a2)->string));
}

int process ARG1(CHAR *, filename)
{
    SM_SOFTKEY	*skey;
    SM_SCREEN	*screenp;
    SM_MENU	*menup;
    int		errors = 0;
    int		i, keyval = 0700, j = 0;
    INDEX	size, index;
    CHAR	sep, *buf;
    ARRAY	keynames = NULL;
    SM_KEYWORD	*kp, keyname;
    FILE	*f;

    buf = alloca(SM_MAXREC);

/* First open filename.def */
    strcpy(buf, filename);
    strcat(buf, ".def");
    if ((f = fopen(buf, "w")) == NULL) {
	fprintf(stderr, "%s: Can't open %s for writing.\n", sm_program_name, buf);
	usage();
    }
    	
/* 1. Output #define's for keystrokes */
    skey = sm_first_skey(sm_user_screens());
    if (skey && *skey) {

	/* Collect all the names into a vector for sorting */
	for (; skey && *skey; skey = sm_next_skey(skey)) 
	    for (i = 0; i < 8; i++)
		if (*((*skey)->key_name[i]))
		    keynames = sm_set_keyword(keynames, j++, 
					      (*skey)->key_name[i], 
					      (*skey)->key_help[i]);
    }

    for (menup = sm_first_menu(sm_user_screens());
	 menup && *menup;
	 menup = sm_next_menu(menup)) {
	INDEX	i;

	for (i = 0; i < arrayLength((*menup)->items); i++) {
	    CHAR		*command;
	    SM_MENU_ITEM	menu_item;

	    menu_item = (SM_MENU_ITEM) arrayItem((*menup)->items, i);
	    command = menu_item->command;
	    /* command= '>menu_name' just gives a new menu */
	    if (command && *command && (*command != '>'))
		keynames = sm_set_keyword(keynames, j++, command, "");
	}
    }

    size = arrayLength(keynames);

    if (size) {
	qsort((CHAR *) firstArrayItemp(keynames), 
	      (int)size, 
	      sizeof(CHAR *), 
	      compare_skey);
	
	/* Eliminate duplicates - use 'index' rather than pointers since 
	   keynames could be realloc'd by removeFromArray */
	index = 0;	
	while (index < arrayLength(keynames)) {
	    INDEX	index2 = index + 1;
	    SM_KEYWORD 	k2;

	    while (index2 < arrayLength(keynames)) {
		keyname = (SM_KEYWORD) arrayItem(keynames, index);
		k2      = (SM_KEYWORD) arrayItem(keynames, index2);
	    
		if (strcmp(keyname->string, k2->string) == 0) {
		    sm_destroy_keyword((SM_KEYWORD *) arrayItemp(keynames, index2));
		    continue;
		}
		index2++;
	    }
	    index++;
	}

	/* Now, output definitions - UNLESS already an SM_ command */
	for (kp = (SM_KEYWORD *) firstArrayItemp(keynames); 
	     kp && *kp; 
	     kp = (SM_KEYWORD *) nextArrayItemp(keynames, (void *) kp)) {
	    if ((*kp)->string) {
		strcpy(buf, (*kp)->string);
		if (sm_lookup_keyword(sm_command_table, buf) == SM_ERROR) {
		    if (sm_fix_name(buf))
			fprintf(stderr, "%s: key name \"%s\" changed to \"%s\".\n",
				sm_program_name,
				(*kp)->string, buf);
		    sm_toupper(buf);
		    fprintf(f, "#define %s 0%o\n", buf, keyval++);
		}
	    }
	}
    }

    fprintf(f, "#ifndef SM_CLASS\n#define SM_CLASS\n#endif\n\n");

/* 2. Output global SM_SCREEN declarations */
    screenp = sm_first_scr(sm_user_screens());
    if (screenp && *screenp) {
	fprintf(f, "\n");
	fprintf(f, "SM_CLASS SM_SCREEN");
	sep = ' ';
	for (; *screenp; screenp = sm_next_scr(screenp)) 
	    if (*(*screenp)->screen_name) {
		strcpy(buf, (*screenp)->screen_name);
		if (sm_fix_name(buf))
		    fprintf(stderr, "%s: screen name \"%s\" changed to \"%s\".\n",
			    sm_program_name,
			    (*screenp)->screen_name, buf);
		sm_tolower(buf);
		fprintf(f, "%c %s", sep, buf);
		sep = ',';
	    }
	fprintf(f, ";\n");
    }

/* 3. Output global SM_SOFTKEY declarations */
    skey = sm_first_skey(sm_user_screens());
    if (skey && *skey) {
	fprintf(f, "\n");
	fprintf(f, "SM_CLASS SM_SOFTKEY");
	sep = ' ';
	for (; *skey; skey = sm_next_skey(skey))
	    if (*(*skey)->skey_name) {
		strcpy(buf, (*skey)->skey_name);
		if (sm_fix_name(buf))
		    fprintf(stderr, "%s: key set name \"%s\" changed to \"%s\".\n",
			    sm_program_name,
			    (*skey)->skey_name, buf);
		sm_tolower(buf);
		fprintf(f, "%c %s", sep, buf);
		sep = ',';
	    }
	fprintf(f, ";\n");
    }

/* Now open filename.opn file */
    fclose(f);
    strcpy(buf, filename);
    strcat(buf, ".opn");
    if ((f = fopen(buf, "w")) == NULL) {
	fprintf(stderr, "%s: Can't open %s for writing.\n", sm_program_name, buf);
	usage();
    }

/* 4. Output sm_scr_open statements */
    screenp = sm_first_scr(sm_user_screens());
    if (screenp && *screenp) {
        fprintf(f, "\n");
	for (; *screenp; screenp = sm_next_scr(screenp)) 
	    if (*(*screenp)->screen_name) {
		strcpy(buf, (*screenp)->screen_name);
		sm_fix_name(buf);
		sm_tolower(buf);
		fprintf(f, 
"    if ((%s = sm_scr_open(screenset, \"%s\")) == NULL)\n", 
			buf, 
			(*screenp)->screen_name);
		fprintf(f, "        sm_error_exit(\"Can't open screen %s\");\n", 
			(*screenp)->screen_name);
	    }
    }

/* 5. Output sm_open_skey statements */    
    skey = sm_first_skey(sm_user_screens());
    if (skey && *skey) {
	fprintf(f, "\n");
	for (; *skey; skey = sm_next_skey(skey)) 
	    if (*(*skey)->skey_name) {
		strcpy(buf, (*skey)->skey_name);
		sm_fix_name(buf);
		sm_tolower(buf);
		fprintf(f, 
"    if ((%s = sm_skey_open(screenset, \"%s\")) == NULL)\n", 
			buf, 
			(*skey)->skey_name);
		fprintf(f, "        sm_error_exit(\"Can't open softkey %s\");\n", 
			(*skey)->skey_name);
	    }
    }

/* 6. Output sm_set_command statements - UNLESS already an sm_command */
    skey = sm_first_skey(sm_user_screens());
    if (skey && *skey) {
	fprintf(f, "\n");
	for (kp = (SM_KEYWORD *) firstArrayItemp(keynames); 
	     kp && *kp; 
	     kp = (SM_KEYWORD *) nextArrayItemp(keynames, (void *) kp)) {
	    if ((*kp)->string) {
		strcpy(buf, (*kp)->string);
		if (sm_lookup_keyword(sm_command_table, buf) == SM_ERROR) {
		    sm_fix_name(buf);
		    sm_toupper(buf);
		    fprintf(f, "    if (sm_set_command(%s, \"%s\", ",
			    buf, 
			    (*kp)->string);
		    if ((*kp)->help)
			fprintf(f, "\"%s\"", (*kp)->help);
		    else
			fprintf(f, "NULL");
		    fprintf(f, "))\n");
		    fprintf(f, "        sm_error_exit(\"Error setting keyword %s\");\n", 
			    buf);
		}
	    }
	}
	fprintf(f, "\n");
    }

    fclose(f);
    sm_destroy_all_keywords(keynames);
    freeArray(keynames);

    return(errors);		
}

int main(argc, argv)
    int		argc;
    CHAR	**argv;
{
    int		c,
    		errors = 0;
    CHAR	*filename;

    sm_pre_init(argc, argv);

    while ((c = getopt(argc, argv, "h?")) != EOF)
        switch (c) {
        case '?':
        default:
            usage();
            break;
        }

    if (setjmp(NoMoreHeap)) {
	fprintf(stderr, "Ran out of heap!\n");
	exit(1);
    }

    sm_init(0, argc, argv);
    /*smio_term();*/

    if (optind >= argc)
	usage();
    else
        for (; optind < argc; optind++) {
	    CHAR *p;

	    sm_clear_out(0);
	    filename = argv[optind];
            if (sm_fopen(sm_user_screens(), filename) == SM_ERROR)
		usage();
	    if ((p = strrchr(filename, '.')) != NULL)
		*p = 0;
	    errors += process(filename);
	}

    exit(errors);
}


/* For emacs:
 * Local Variables:
 * tab-width: 8
 * End:
 */
